﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using PipeServer.Config;
using PipeServer.Interface;
using PipeServer.Model;
using PipeServer.Server;
using PipeServer.SystemAllot;

using RpcHelper;

namespace PipeServer
{
        public class PipeServer
        {
        private static Timer _CheckTimer;
                static PipeServer ()
                {
                        SocketBuffer.BufferCollect.InitBuffer ();
            _CheckTimer=new Timer (new TimerCallback (_CheckIsCon), null, 60000, 60000);
                }
                private static void _CheckIsCon (object state)
                {
                        PipeServer.CheckClientIsCon ();
                }


                private static readonly Dictionary<string, ServerInfo> serverList = new Dictionary<string, ServerInfo> ();

                public static string DefaultPipeName => Config.PipeConfig.DefaultPipeName;

                private static void InitServer ()
                {
                        IAllot allot = Config.PipeConfig.DefaultAllot;
                        if (allot == null)
                        {
                                allot = new UserAllotInfo ();
                        }
                        AddServer (Config.PipeConfig.DefaultPipeName, allot);
                }


                /// <summary>
                /// 注册一个新的管道服务
                /// </summary>
                /// <param name="port"></param>
                public static void AddServer (string pipeName, Interface.IAllot allot)
                {
                        if (allot == null)
                        {
                                throw new ErrorException ("ipc.allot.null");
                        }
                        else if (serverList.ContainsKey (pipeName))
                        {
                                throw new ErrorException ("ipc.pipe.name.repeat");
                        }
                        Server.ServerInfo objServer = new ServerInfo (pipeName, allot, Config.PipeConfig.PipeEvent, Config.PipeConfig.ServerKey);
                        serverList.Add (pipeName, objServer);
                        objServer.InitServer ();
                }
                public static void AddServer (string pipeName, Interface.IAllot allot, IPipeEvent socketEvent)
                {
                        AddServer (pipeName, allot, socketEvent, Config.PipeConfig.ServerKey);
                }
                /// <summary>
                /// 注册一个新的Socket服务
                /// </summary>
                /// <param name="port"></param>
                public static void AddServer (string pipeName, IAllot allot, IPipeEvent socketEvent, string punlicKey)
                {
                        if (allot == null)
                        {
                                throw new ErrorException ("ipc.allot.null");
                        }
                        else if (serverList.ContainsKey (pipeName))
                        {
                                throw new ErrorException ("ipc.pipe.name.repeat");
                        }
                        punlicKey = Tools.GetMD5 (punlicKey);
                        Server.ServerInfo objServer = new Server.ServerInfo (pipeName, allot, socketEvent, punlicKey);
                        serverList.Add (pipeName, objServer);
                        objServer.InitServer ();
                }
                public static int GetSocketClientNum (string pipeName)
                {
                        if (serverList.ContainsKey (pipeName))
                        {
                                return serverList[pipeName].ClientCount;
                        }
                        return 0;
                }

                internal static bool CheckPublicKey (string pipeName, string key)
                {
                        if (serverList.TryGetValue (pipeName, out Server.ServerInfo server))
                        {
                                return server.PublicKey == key;
                        }
                        return false;
                }

                internal static void BatchSend<T> (string pipeName, string type, T data, Guid[] clientId, int timeOut, int syncTimeOut)
                {
                        if (serverList.TryGetValue (pipeName, out ServerInfo server))
                        {
                                Page page = Page.GetBatchDataPage (type, data, timeOut, syncTimeOut);
                                foreach (Guid i in clientId)
                                {
                                        if (server.GetClient (i, out IClient client, out _))
                                        {
                                                client.Send (page, out _);
                                        }
                                }
                        }
                }


                public static void CloseClient (params Guid[] clientId)
                {
                        if (clientId != null)
                        {
                                CloseClient (PipeConfig.DefaultPipeName, clientId);
                        }
                }
                public static void CloseClient (string pipeName, params Guid[] clientId)
                {
                        if (clientId != null)
                        {
                                if (serverList.TryGetValue (pipeName, out ServerInfo server))
                                {
                                        foreach (Guid i in clientId)
                                        {
                                                server.CloseClient (i);
                                        }
                                }
                        }
                }

                /// <summary>
                /// 客户端关闭事件
                /// </summary>
                /// <param name="clientId"></param>
                internal static void ClientCloseEvent (string pipeName, Guid clientId)
                {
                        if (serverList.TryGetValue (pipeName, out ServerInfo server))
                        {
                                server.ClientCloseEvent (clientId);
                        }
                }

                internal static void CloseClient (string pipeName, Guid clientId)
                {
                        if (serverList.TryGetValue (pipeName, out ServerInfo server))
                        {
                                server.CloseClient (clientId);
                        }
                }

                public static void CloseServer ()
                {
                        foreach (Server.ServerInfo i in serverList.Values)
                        {
                                i.CloseServer ();
                        }
                        LogSystem.CloseLog ();
                }

                public static void CloseServer (string pipeName)
                {
                        Server.ServerInfo server = serverList.Values.Where (a => a.PipeName == pipeName).FirstOrDefault ();
                        if (server != null)
                        {
                                server.CloseServer ();
                        }
                }

                internal static void CheckClientIsCon ()
                {
                        foreach (ServerInfo i in serverList.Values)
                        {
                                i.CheckIsCon ();
                        }
                }



                internal static bool GetServer (string pipeName, out ServerInfo server)
                {
                        return serverList.TryGetValue (pipeName, out server);
                }
                internal static bool GetServer (string pipeName, out ServerInfo server, out string error)
                {
                        if (!serverList.TryGetValue (pipeName, out server))
                        {
                                error = "pipe.server.not.find";
                                return false;
                        }
                        error = null;
                        return true;
                }
                public static void Init ()
                {
                        InitServer ();
                }
        }
}
